﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AsyncEvtEcho
{
    sealed class Header
    {
        // *************************************************************** //
        #region [ member fields ]

        public const int BinaryLength = 8;

        private int m_cmd;
        private int m_size;

        #endregion

        // *************************************************************** //
        #region [ public APIs ]

        #region "properties"

        public int Command
        {
            set { m_cmd = value; }
            get { return m_cmd; }
        }

        public int Size
        {
            set { m_size = value; }
            get { return m_size; }
        }

        #endregion

        #region "methods"

        public byte[] BinaryImage
        {
            get
            {
                byte[] binImage = new byte[BinaryLength];
                Buffer.BlockCopy(BitConverter.GetBytes(m_cmd), 0, binImage, 0, 4);
                Buffer.BlockCopy(BitConverter.GetBytes(m_size), 0, binImage, 4, 4);
                return binImage;
            }
        }

        public int Deserialize(byte[] binImage, int offset)
        {
            int position = offset;

            m_cmd = BitConverter.ToInt32(binImage, position);
            position += 4;

            m_size = BitConverter.ToInt32(binImage, position);
            position += 4;

            return position - offset;
        }

        #endregion

        #region "override methods"

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            if (object.ReferenceEquals(this, obj))
                return true;

            if (!(obj is Header))
                return false;
            else
            {
                Header other = (Header)obj;
                return (this.m_cmd == other.m_cmd) && (this.m_size == other.m_size);
            }
        }

        public override int GetHashCode()
        {
            return string.Format("{0}:{1}", m_cmd, m_size).GetHashCode();
        }

        #endregion

        #endregion
    }

    sealed class HeadState : RecvStateBase
    {
        private readonly Header m_header;

        public HeadState(HeadBodyRecver context)
            : base(context)
        {
            m_buffer = new byte[Header.BinaryLength];
            m_header = new Header();
        }

        public Header Header { get { return m_header; } }

        #region [ override methods ]

        protected override bool End()
        {
            m_header.Deserialize(m_buffer, 0);
            m_context.OnHeadReceived(m_header);
            return false;// we only read a complete head, so return false to indicate that there is "body" to read
        }

        public override int WholeLength
        {
            get { return Header.BinaryLength; }
            set { throw new InvalidOperationException("should not be invoked"); }
        }

        #endregion
    }
}
